home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / programer2 / pari2 / pari / other / pari_el < prev    next >
Lisp/Scheme  |  1991-11-13  |  19KB  |  603 lines

  1. ;; This is the interface for pari under emacs
  2. ;; The main commands in this file are
  3. ;; M-x gp      Opens a buffer for interaction with gp and then starts gp.
  4. ;; C-u M-x gp  Like M-x gp, but prompts for command line arguments.
  5. ;; M-x gpman   Displays the gp-pari manual using any dvi preview program.
  6.  
  7. ;; All functions of gp are preserved.
  8.  
  9. ;; This version by David Carlisle (JANET: carlisle@uk.ac.man.cs).
  10. ;; The original pari.el was written by Annette Hoffman.
  11.  
  12.  
  13. ;; Version 2.8 (22/4/91)
  14.  
  15. ;; See  pari.txt  for more details.
  16.  
  17.  
  18. (provide 'gp)
  19.  
  20. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  21.  
  22. ;; The following five  constants (aka variables !) should be
  23. ;; set for each site.
  24.  
  25. (defconst gp-chap3 "~pari/PARISOURCES/tex/usersch3.tex"
  26.   "The TeX source for chapter 3 of the PARI-GP manual")
  27.  
  28. (defconst gp-file-name "/usr/local/bin/gp"
  29.   "The file name of the gp executable file")
  30.  
  31. (defconst gp-man-dvi "~pari/SPARC/tex/users.dvi" 
  32.  "dvi version of the manual")
  33.  
  34. (defconst  gp-menu "~pari/PARISOURCES/pari.menu"
  35.    "menu file")
  36.  
  37. (defconst gp-dvi-preview "xdvi -s 3"
  38. ;; (defconst gp-dvi-preview "texsun"
  39.   "dvi previewer (and options)")
  40.  
  41. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  42.  
  43. ;; Individual users may want re-set some of the variables in this section
  44. ;; in a gp-mode-hook in their .emacs file.
  45. ;; See pari.txt for an example of a gp-mode-hook.
  46.  
  47. (defvar gp-stack-size "4000000"
  48.   "Default stack size: passed to the progam gp.")
  49.  
  50. (defvar gp-buffer-size "30000"
  51.   "Default buffer size: passed to the progam gp.")
  52.  
  53. (defvar gp-prime-limit "500000"
  54.   "Default prime limit: passed to the progam gp.")
  55.  
  56. (defvar gp-prompt-for-args nil
  57.   "A non-nil value makes M-x gp act like C-u M-x gp, 
  58.    ie prompt for the command line arguments.")
  59.  
  60. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  61.  
  62. (defvar gp-prompt-pattern
  63.   "---- (type return to continue) ----\\|\\?[\C-j\t ]*"
  64.   "Regexp used to match gp prompts.
  65.    can be set with gp-set-prompt (bound to M-\\ p)")
  66.  
  67.  
  68. (defvar gp-map (make-sparse-keymap)
  69.   "Local keymap used in buffer *PARI*.")
  70.  
  71. (define-key gp-map "\C-m"    'gp-send-input)
  72. (define-key gp-map "\M-\C-m" 'gp-copy-input)
  73. (define-key gp-map "\M-\\p"  'gp-set-prompt)
  74. (define-key gp-map "\M-\\t"  'gp-meta-t)
  75. (define-key gp-map "\M-\\d"  'gp-meta-d)
  76.  
  77. (define-key gp-map "\M-\\r"  'gp-meta-r)
  78. (define-key gp-map "\M-\\w"  'gp-meta-w)
  79. (define-key gp-map "\M-\\v"  'gp-meta-v)
  80. (define-key gp-map "\M-\\x"  'gp-meta-x)
  81. (define-key gp-map "\M-\\s"  'gp-meta-s)
  82. (define-key gp-map "\M-\\b"  'gp-meta-b)
  83. (define-key gp-map "\M-\\k"  'gp-meta-k)
  84. (define-key gp-map "\M-\\q"  'gp-meta-q)
  85. (define-key gp-map "\M-?"    'gp-get-man-entry)
  86. (define-key gp-map "\M-\\c"  'gp-menu)    
  87. (define-key gp-map "\M-\\\\"  'gp-break-long-line)
  88. (define-key gp-map "\C-c"    'gp-interrupt)
  89.  
  90. (defvar gp-process nil "")
  91. (defvar gp-man-process nil "")
  92.  
  93. (defun gp (flag)
  94.   "
  95.    Open a buffer and a window for the execution of gp.
  96.  
  97.    The following bindings are available:
  98.    \\{gp-map}
  99.  
  100.   The variables
  101.   gp-file-name gp-stack-size gp-buffer-size gp-prime-limit
  102.   determine the command line that starts gp.
  103.   To override the default settings, give gp a prefix argument.
  104.   C-u M-x gp ."
  105.   (interactive "P")
  106. ;; Create buffer *PARI* and make it become the current buffer.
  107.   (switch-to-buffer "*PARI*") 
  108.   (goto-char (point-max))
  109.   (if gp-process
  110.     nil
  111.     (kill-all-local-variables)
  112.     (setq major-mode 'gp)
  113.     (setq mode-name "GP")
  114. ;; Set up user preferences.
  115.     (run-hooks 'gp-mode-hook)
  116.  
  117. ;; Make gp-map the local map of buffer *PARI*.
  118.     (use-local-map gp-map)      
  119.     (setq mode-line-process '(": %s"))
  120.  
  121. ;; Form the command line string.
  122.     (let* (
  123.       (flag (or flag gp-prompt-for-args))
  124.       (gp-command
  125.       (concat
  126.         (gp-read-input "Gp executable ?" gp-file-name "" flag)
  127.         (gp-read-input "Stack size ?" gp-stack-size " -s " flag)
  128.         (gp-read-input "Buffer size ?" gp-buffer-size " -b " flag)
  129.         (gp-read-input "Prime limit ?" gp-prime-limit " -p " flag))))
  130. ;; Insert the command line string into the *PARI* buffer.
  131. ;; (This is just for reference.)
  132.       (insert (concat "\n" gp-command "\n"))
  133. ;; Start gp.
  134.       (setq gp-process
  135.         (start-process 
  136.           "pari" "*PARI*" shell-file-name "-c" 
  137.             (concat "stty nl; exec " gp-command))))
  138. ;; Clean up when the gp process has finished.
  139.       (set-process-sentinel gp-process  'gp-sentinel)))
  140.  
  141. (defun gp-read-input (prompt default sep flag)
  142. " If flag is non-nil, reads string then if string is \"\" uses default.
  143.   If flag is nil then string is the default.
  144.   If resulting string is not \"\" prepends sep.
  145.   As a special case, if string is a space, return \"\"."
  146.   (let ((string 
  147.     (if flag
  148. ;; If flag is non-nil prompt for input from mini-buffer.
  149.       (read-input 
  150.         (concat prompt " (Default "default") "))
  151. ;; Else use the default string.
  152.         default)))
  153.     (if (equal string "")
  154.       (if (equal default "") 
  155. ;; If sting and default both "": 
  156.          ""
  157. ;; If string "" and default is non empty:
  158.          (concat sep default))
  159.       (if (equal string " ")
  160. ;; If string is a space:
  161.         ""
  162. ;; If string is non empty:
  163.         (concat sep string)))))
  164.  
  165.  
  166.  
  167. (defun gp-sentinel (proc msg)
  168.   "Sentinel for the gp-process in buffer *PARI*."
  169.     (if (get-buffer "*PARI*")
  170.       (progn
  171.         (set-buffer "*PARI*")
  172.         (goto-char (point-max))
  173.         (insert msg)
  174.         (delete-windows-on "*PARI*")))
  175.     (if (get-buffer "*gp-help*") (kill-buffer "*gp-help*"))
  176.     (let ((b (get-file-buffer gp-chap3))) (if b (kill-buffer b)))
  177.     (let ((b (get-file-buffer gp-menu)))  (if b (kill-buffer b)))
  178.     (if (file-exists-p gp-temp-file) 
  179.        (progn (shell-command (concat "rm " gp-temp-file)) 
  180.               (message "Removing %s" gp-temp-file )))
  181.   (setq gp-process nil))
  182.  
  183.  
  184. (defun gpman()
  185.   "Start up xdvi with the gp manual."
  186.   (interactive)
  187. ;; Run gp-mode-hook in case it specifies a different
  188. ;; version of the manual.
  189.   (run-hooks 'gp-mode-hook)
  190.   (set-buffer (get-buffer-create "*GP-MAN*"))
  191.   (if gp-man-process
  192.      nil
  193. ;; Start xdvi.
  194.     (message (concat "Starting " gp-dvi-preview " " gp-man-dvi))
  195.     (setq gp-man-process
  196.       (start-process "gp-man" "*GP-MAN*"
  197.           shell-file-name
  198.           "-c" (concat "exec " gp-dvi-preview " " gp-man-dvi)))
  199.     (set-process-sentinel gp-man-process 'gp-man-sentinel)))
  200.  
  201. (defun gp-man-sentinel (proc msg)
  202.   "Sentinel for the gp-man-process in buffer *GP-MAN*."
  203.   (let ((buf (process-buffer proc)))
  204.     (if buf (kill-buffer buf)))
  205.   (message (concat "gpman: " msg))
  206.   (setq gp-man-process nil))
  207.  
  208. (defun gp-copy-input()
  209.   "Copy expression around point to the end of the buffer.
  210.    (Unless this is already the last expression.)"
  211.   (interactive)
  212. ;; Go back to the end of prompt, and record that point.
  213. ;; If a line contains more than one prompt string, use the FIRST.
  214. ;; This is so that ? ?cos works. (ie gives the help for cos).
  215. ;; We can not insist on prompt at the beginning of a line (ie put
  216. ;; ^ in gp-prompt-pattern) because of the output from print1()
  217.   (re-search-backward gp-prompt-pattern)
  218.   (let ((p (match-end 0)))
  219.     (beginning-of-line)
  220.     (re-search-forward gp-prompt-pattern)
  221.     (setq gp-input-start (point))
  222. ;; Go past the last prompt on this line before looking for end of expression.
  223.     (goto-char p))
  224. ;; Check if we are already at the last expression.
  225.   (let ((nlast (re-search-forward (concat "[\n ]*\\("
  226.          gp-prompt-pattern
  227.          "\\|%[0-9]+ =\\|\\*\\*\\*\\|unused characters\\|time\\)")
  228.              (point-max) t)))
  229. ;; Find the limit of the expression.
  230. ;;   This is the end of buffer,the  prompt, or an error message.
  231.   (let ((limit (if nlast (match-beginning 0) (point-max))))
  232.   (goto-char gp-input-start)
  233. ;; End of expression is a line ending with } if it starts with {,
  234. ;;   otherwise a line not ending with \.
  235.   (let ((end-expression (if (looking-at " *{") "}$" "[^\\]$")))
  236. ;; Look for the end of expression, as far as the limit computed above.
  237.   (setq gp-complete-expression  (re-search-forward end-expression limit 1))
  238.   (setq gp-input-end (point))
  239. ;; If not already the last expression copy to the end of the buffer.
  240.   (if nlast 
  241.    (progn
  242.      (goto-char (point-max))
  243.      (insert (buffer-substring gp-input-start gp-input-end))
  244.      (if gp-complete-expression
  245.        nil
  246.        (ding)
  247.        (message "Incomplete expression."))))))))
  248.  
  249. (setq gp-temp-file (make-temp-name "/usr/tmp/gp_"))
  250.  
  251. (defun gp-send-input ()
  252.   "Send input to gp. Does not send incomplete expressions
  253.    ie those starting with {, without a matching }, or those
  254.    ending with \\ .
  255.    Use a temporary file (and \\r ) for large expressions"
  256.   (interactive)
  257. ;; gp-copy-input does all the work!
  258.   (gp-copy-input)
  259.   (insert "\n")
  260.   (if gp-complete-expression
  261. ;; If it is a complete expression do this:
  262.     (progn
  263.       (if (> (- gp-input-end gp-input-start) 255)
  264. ;; If large expression, use a temporary file.
  265.         (progn 
  266.           (write-region gp-input-start gp-input-end gp-temp-file)
  267.           (process-send-string gp-process (concat "\\r "gp-temp-file"\n")))
  268. ;; Else use process-send-region.
  269.         (process-send-region gp-process gp-input-start gp-input-end)
  270.  
  271.         (process-send-string gp-process "\n"))
  272.       (set-marker (process-mark gp-process) (point)))
  273. ;; Else do this:
  274.     (message "Incomplete expression: Not sent to gp.")))
  275.  
  276.  
  277. (defun gp-interrupt ()
  278.   "Interrupt gp.
  279.    This is identical to interrupt-shell-subjob in shell-mode."
  280.   (interactive)
  281.   (interrupt-process nil t))
  282.  
  283. (defun gp-set-prompt (p)
  284.   "Set new gp prompt (and tell emacs that you have done so).
  285.    Do not put spaces in the argument, or emacs and gp will
  286.    have a different idea about what the prompt is."
  287.   (interactive "sNew prompt: ")
  288. ;; gp-prompt-pattern matches:
  289. ;; (New prompt plus any following white space) OR (Old pattern).
  290.   (setq gp-prompt-pattern 
  291.     (concat (regexp-quote p) "[\C-j\t ]*\\|" gp-prompt-pattern))
  292.   (set-buffer "*PARI*")
  293.   (goto-char (point-max))
  294. ;; Tell gp about the change too!
  295.   (insert (concat "\\prompt="p))
  296.   (gp-send-input))
  297.  
  298. (defun gp-replace (a b)
  299.   "Replace the regexp a by the string b everywhere in the current buffer"
  300.   (goto-char (point-min))
  301.   (while (re-search-forward a (point-max) t)
  302.     (replace-match b t t)))
  303.  
  304. (defun gp-get-man-entry (fn)
  305.   "Obtains the description of fn from chapter 3 of the manual.
  306.   Strips off some (not all) of the TeX syntax, and displays the result
  307.   in a new window.
  308.   If there is no entry for fn in the manual, sends ?fn to gp."
  309.   (interactive "sFunction: ")
  310. ;; Stop TeX-mode being loaded for gp-chap3.
  311.   (let ((auto-mode-alist nil))
  312.     (set-buffer (find-file-noselect gp-chap3)))
  313. ;; Fix up one or two special cases, or 
  314. ;; regexp-quote the argument.
  315.   (let ((qfn (cond
  316.            ((equal fn "\\" ) "\\\\backslash")
  317.            ((equal fn "^" ) "\\\\hat{}")
  318.            ((equal fn "!" ) "fact")
  319.            ((equal fn "~" ) "trans") 
  320.            ((equal fn "_" ) "conj")
  321.            ((equal fn "-" ) "\\+")
  322.            ((equal fn "%" ) "\\\\%")
  323.            ((equal fn "min" ) "max")
  324.            ((equal fn "log" ) "ln")
  325.            ((equal fn "det2" ) "det")
  326.            ((or (equal fn "<=" )(equal fn "<" )(equal fn ">=" )
  327.             (equal fn ">" )(equal fn "==" )(equal fn "!=" )
  328.             (equal fn "||" )(equal fn "&&" )) 
  329.                       "comparison and \\\\ref{boolean operators}")
  330.            ((regexp-quote fn)))))
  331. ;; Find the entry.
  332.   (goto-char (point-min))
  333. ;; Entry starts with \subsec ... fn
  334.   (if (re-search-forward 
  335.      (concat "\\(subsec[\\\\{ref]*[\\${]\\)" qfn "[}\\$]") (point-max) t)
  336. ;; If There is an entry in the manual do this:
  337.   (progn
  338.     (goto-char (match-end 1))
  339.     (let ((copy (buffer-substring (point) 
  340. ;; Entry ends with "The library" or the next (sub-)section.
  341.           (progn (re-search-forward "[tT]he library\\|\\\\[sub]*sec" 
  342.                     (point-max) t) 
  343.                  (match-beginning 0))))
  344.           (wind (selected-window)))
  345. ;; Copy the entry to the help buffer.
  346.     (switch-to-buffer-other-window (get-buffer-create "*gp-help*"))
  347.     (erase-buffer)
  348.     (insert copy)
  349. ;; Strip off some of the TeX. Note the idea is to leave enough
  350. ;; pseudo-TeX so that the entry is understandable. Thus want to
  351. ;; leave:  a^2,  x \over y, etc.
  352.     (gp-replace "\\$-" "-")
  353.     (gp-replace "\\$" " " )
  354.     (gp-replace "\\\\backslash" "\\")
  355.     (gp-replace "\\\\hat" "^")
  356.     (gp-replace
  357. "\\\\smallskip\\|\\\\sref{[ a-z]*}\\|\\\\bf\\|\
  358. \\\\ref\\|\\\\Bbb\\|\\\\text\\|\\\\tt\\|{\\|}"
  359.       "")
  360.     (goto-char (point-min))
  361.     (select-window wind)))
  362. ;; Else there is no entry in the manual. So send ?fn to gp.
  363.   (set-buffer "*PARI*")
  364.   (gp-meta-command (concat "?" fn)))))
  365.  
  366. (defun gp-meta-command (command)
  367.   "Send command to gp, and display output in help buffer"
  368.   (goto-char (point-max))
  369.   (let ((temp (point)) (wind (selected-window)))
  370. ;; Send the meta command to gp.
  371.   (process-send-string gp-process (concat command "\n"))
  372. ;; Wait for the gp-prompt to be sent.
  373.   (gp-wait-for-output)
  374. ;; Display the output in the help buffer.
  375.   (let ((copy (buffer-substring temp (point-max))))
  376.   (delete-region temp (point-max))
  377.   (switch-to-buffer-other-window (get-buffer-create "*gp-help*"))
  378.   (erase-buffer)
  379.   (insert copy)
  380.   (beginning-of-line)
  381.   (delete-region (point) (point-max))
  382.   (goto-char (point-min))
  383.   (select-window wind))))
  384.  
  385. (defun gp-wait-for-output ()
  386.   "Hang around until the prompt appears."
  387.   (setq ndone t)
  388.   (while ndone 
  389.   (accept-process-output "*PARI*")
  390.   (let ((p (point))) 
  391.  
  392.     (beginning-of-line)
  393.     (if (looking-at gp-prompt-pattern)
  394.       (progn (message "done") (setq ndone nil))
  395.       (message "Waiting for gp output ..."))
  396.     (goto-char p))))
  397.  
  398. (defun gp-meta-d ()
  399.   "Sends \\d to gp, then displays output in the help buffer.
  400.   Prints the gp defaults."
  401.   (interactive)
  402.   (gp-meta-command "\\d"))
  403.  
  404. (defun gp-meta-t ()
  405.   "Sends \\t to gp, then displays output in the help buffer.
  406.   Prints the longword format of PARI types."
  407.   (interactive)
  408.   (gp-meta-command "\\t"))
  409.  
  410. (defun gp-meta-r (file)
  411.   "Sends a \\r <file name> comand to gp.
  412.    Reads in gp commands from a file.
  413.    See gp-meta-r"
  414.   (interactive "fRead from file: ")
  415.   (goto-char (point-max))
  416.   (insert (concat "\\r " (expand-file-name file)))
  417.   (gp-send-input))
  418.  
  419. (defun gp-meta-w (file num)
  420.   "Sends a \\w<num> <file name> comand to gp.
  421.   Writes gp object %<num> to <file name>."
  422.   (interactive "FWrite to file: \nsObject number %%")
  423.   (goto-char (point-max))
  424.   (insert (concat "\\w"num" " (expand-file-name file)))
  425.   (gp-send-input))
  426.  
  427. (defun gp-meta-x ()
  428.   "Sends \\x to gp, then displays output in the help buffer.
  429.   Prints tree of addresses and contents of last object."
  430.   (interactive)
  431.   (gp-meta-command "\\x"))
  432.  
  433. (defun gp-meta-v ()
  434.   "Sends \\v to gp, then displays output in the help buffer.
  435.   Prints the version number of this implementation of pari-gp."
  436.   (interactive)
  437.   (gp-meta-command "\\v"))
  438.  
  439. (defun gp-meta-s (num)
  440.   "Sends \\s or \\s(num) to gp, then displays output in the help buffer.
  441.   Prints the state of the pari stack."
  442.   (interactive "sNumber of longwords (default 0) ")
  443.   (if (equal num "")
  444.     (gp-meta-command "\\s")
  445.     (gp-meta-command (concat "\\s(" num ")" ))))
  446.  
  447. (defun gp-meta-b (num)
  448.   "Sends \\b or \\b<num> to gp, then displays output in the help buffer.
  449.   Prints object %<num> in pretty format (unless \\p set)."
  450.   (interactive "sPrint object (default last) %%")
  451.   (if (equal num "")
  452.     (gp-meta-command "\\b")
  453.     (gp-meta-command (concat "\\b" num))))
  454.  
  455. (defun gp-meta-k ()
  456.   "Sends \\k to gp.
  457.   Prompts for confirmation before 
  458.   re-initialising gp and clearing the buffer."
  459.   (interactive) 
  460.   (if (y-or-n-p "Re-initialise gp ? ") 
  461.     (progn
  462.       (set-buffer "*PARI*")
  463.       (goto-char (point-max))
  464.       (insert "\\k\n")
  465.       (set-marker (process-mark gp-process) (point))
  466.       (if (y-or-n-p "Clear *PARI* buffer ? ")
  467.          (erase-buffer))
  468.      (process-send-string gp-process "\\k\n")))
  469.   (message ""))
  470.  
  471. (defun gp-meta-q ()
  472.   "Sends \\q to gp.
  473.   Prompts for confirmation before quiting."
  474.   (interactive) 
  475.   (if (y-or-n-p "Quit gp ? ") 
  476.     (progn
  477.      (set-buffer "*PARI*")
  478.      (goto-char (point-max))
  479.      (process-send-string gp-process "\\q\n")))
  480.   (message ""))
  481.  
  482.  
  483. (defun gp-break-long-line ()
  484.   "gp will not accept lines longer than 256.
  485.    gp-break-long-lines breaks current line 
  486.    inserting \\ every 100 chars."
  487.   (interactive)
  488.   (beginning-of-line)
  489.   (move-to-column 100)
  490.   (while (not (looking-at "$"))
  491.     (insert "\\\n")
  492.     (move-to-column 100)))
  493.  
  494.  
  495.  
  496.  
  497. ;;; The gp help mode.
  498.  
  499. (defun gp-menu ()
  500.   "Major-mode for the gp menu buffer.
  501. The available commands are
  502. \\{gp-menu-map}"
  503.   (interactive)
  504.   (find-file-other-window gp-menu)
  505.   (setq buffer-read-only t)
  506.   (kill-all-local-variables)
  507.   (setq major-mode 'gp-menu)
  508.   (setq mode-name "GP MENU")
  509.   (use-local-map gp-menu-map)
  510.   (gp-menu-main))
  511.  
  512. (defun gp-menu-info ()
  513.   (message "SPC=next DEL=previous RET=select m=main-menu q=quit s=scroll-help"))
  514.  
  515. (defun gp-menu-next ()
  516.   "Move down one line of the gp help menu. (Go to top if at the end.)"
  517.   (interactive)
  518.   (gp-menu-info)
  519.   (forward-line 1)
  520.   (if (eobp) 
  521.     (progn (ding) (goto-char (point-min)))))
  522.  
  523. (defun gp-menu-previous ()
  524.   "Move up one line of the gp help menu. (Go to bottom if at the top.)"
  525.   (interactive)
  526.   (gp-menu-info)
  527.   (if (bobp) 
  528.     (progn (ding) (goto-char (point-max)) (beginning-of-line)) 
  529.     (forward-line -1)))
  530.  
  531. (defun gp-menu-quit ()
  532.   "Switch the *PARI* buffer if it exists, or (other-buffer) if it does not."
  533.   (interactive)
  534.   (let ((w (get-buffer-window "*PARI*"))
  535.         (b (get-buffer "*PARI*")) )
  536.     (cond
  537.      (w (progn (delete-window)(select-window w)))
  538.      (b (switch-to-buffer b))
  539.      (t (switch-to-buffer (other-buffer))))))
  540.  
  541. (defun gp-menu-select ()
  542.   "Select a subject from the main menu, or a manual entry from a subject menu."
  543.   (interactive)
  544.   (if main-menu 
  545. ;; RET in main menu.
  546.     (progn
  547.       (setq main-menu nil)
  548.       (widen)
  549.       (beginning-of-line)
  550.       (let ((sect (buffer-substring 
  551.            (point) (progn (end-of-line) (point)))))
  552.          (narrow-to-region
  553.            (progn 
  554.              (re-search-forward (concat "^###" sect))
  555.              (forward-line 1) (point))
  556.            (progn (re-search-forward "\C-j###" ) (match-beginning 0))))
  557.       (goto-char (point-min)))
  558. ;; RET in subject menu.
  559.     (beginning-of-line)
  560.     (gp-get-man-entry (buffer-substring
  561.       (point)
  562.       (progn (end-of-line) (point)))))
  563.   (gp-menu-info))
  564.  
  565.  
  566.  
  567. (defun gp-menu-main ()
  568.   "Display the main menu."
  569.   (interactive)
  570.   (gp-menu-info)
  571.   (widen)
  572.   (goto-char (point-min))
  573.   (narrow-to-region (point)
  574.     (progn (re-search-forward "\C-j###") (match-beginning 0)))
  575.   (goto-char (point-min))
  576.   (setq done nil)
  577.   (setq main-menu t))
  578.  
  579. (defun gp-menu-scroll ()
  580.   "Scroll the gp help window if it is visible"
  581.   (interactive)
  582.   (gp-menu-info)
  583.   (if (get-buffer-window "*gp-help*") 
  584.     (let ((wind (selected-window)))
  585.       (switch-to-buffer-other-window  "*gp-help*")
  586.       (if (pos-visible-in-window-p (point-max))
  587.          (goto-char (point-min))
  588.          (scroll-up))
  589.       (select-window wind))))
  590.      
  591.  
  592. (defvar gp-menu-map (make-sparse-keymap)
  593.   "Local keymap used in gp menu buffer.")
  594.       
  595.  
  596. (define-key gp-menu-map " "    'gp-menu-next)
  597. (define-key gp-menu-map "\C-?" 'gp-menu-previous)
  598. (define-key gp-menu-map "\C-m" 'gp-menu-select)
  599. (define-key gp-menu-map "q"    'gp-menu-quit)
  600. (define-key gp-menu-map "m"    'gp-menu-main)
  601. (define-key gp-menu-map "s"    'gp-menu-scroll)
  602.  
  603.